home *** CD-ROM | disk | FTP | other *** search
/ PC World Komputer 2010 April / PCWorld0410.iso / hity wydania / Blender 2.49b / blender-2.49b-windows.exe / $_4_ / .blender / scripts / mesh_skin.py < prev    next >
Text File  |  2009-08-31  |  18KB  |  640 lines

  1. #!BPY
  2.  
  3. """
  4. Name: 'Skin Faces/Edge-Loops'
  5. Blender: 243
  6. Group: 'MeshFaceKey'
  7. Tooltip: 'Select 2 vert loops, then run this script.'
  8. """
  9.  
  10. __author__ = "Campbell Barton AKA Ideasman"
  11. __url__ = ["blenderartists.org", "www.blender.org"]
  12. __version__ = "1.1 2006/12/26"
  13.  
  14. __bpydoc__ = """\
  15. With this script vertex loops can be skinned: faces are created to connect the
  16. selected loops of vertices.
  17.  
  18. Usage:
  19.  
  20. In mesh Edit mode select the vertices of the loops (closed paths / curves of
  21. vertices: circles, for example) that should be skinned, then run this script.
  22. A pop-up will provide further options, if the results of a method are not adequate try one of the others.
  23. """
  24.  
  25.  
  26. # $Id: mesh_skin.py 20333 2009-05-22 03:45:46Z campbellbarton $
  27. #
  28. # -------------------------------------------------------------------------- 
  29. # Skin Selected edges 1.0 By Campbell Barton (AKA Ideasman)
  30. # -------------------------------------------------------------------------- 
  31. # ***** BEGIN GPL LICENSE BLOCK ***** 
  32. # This program is free software; you can redistribute it and/or 
  33. # modify it under the terms of the GNU General Public License 
  34. # as published by the Free Software Foundation; either version 2 
  35. # of the License, or (at your option) any later version. 
  36. # This program is distributed in the hope that it will be useful, 
  37. # but WITHOUT ANY WARRANTY; without even the implied warranty of 
  38. # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
  39. # GNU General Public License for more details. 
  40. # You should have received a copy of the GNU General Public License 
  41. # along with this program; if not, write to the Free Software Foundation, 
  42. # Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA. 
  43. # ***** END GPL LICENCE BLOCK ***** 
  44. # -------------------------------------------------------------------------- 
  45.  
  46. # Made by Ideasman/Campbell 2005/06/15 - cbarton@metavr.com
  47.  
  48. import Blender
  49. import bpy
  50. from Blender import Window
  51. from Blender.Mathutils import MidpointVecs, Vector
  52. from Blender.Mathutils import AngleBetweenVecs as _AngleBetweenVecs_
  53. import BPyMessages
  54.  
  55. from Blender.Draw import PupMenu
  56.  
  57. BIG_NUM = 1<<30
  58.  
  59. global CULL_METHOD
  60. CULL_METHOD = 0
  61.  
  62. def AngleBetweenVecs(a1,a2):
  63.     try:
  64.         return _AngleBetweenVecs_(a1,a2)
  65.     except:
  66.         return 180.0
  67.  
  68. class edge(object):
  69.     __slots__ = 'v1', 'v2', 'co1', 'co2', 'length', 'removed', 'match', 'cent', 'angle', 'next', 'prev', 'normal', 'fake'
  70.     def __init__(self, v1,v2):
  71.         self.v1 = v1
  72.         self.v2 = v2
  73.         co1, co2= v1.co, v2.co
  74.         self.co1= co1
  75.         self.co2= co2
  76.         
  77.         # uv1 uv2 vcol1 vcol2 # Add later
  78.         self.length = (co1 - co2).length
  79.         self.removed = 0    # Have we been culled from the eloop
  80.         self.match = None    # The other edge were making a face with
  81.         
  82.         self.cent= MidpointVecs(co1, co2)
  83.         self.angle= 0.0
  84.         self.fake= False
  85.  
  86. class edgeLoop(object):
  87.     __slots__ = 'centre', 'edges', 'normal', 'closed', 'backup_edges'
  88.     def __init__(self, loop, me, closed): # Vert loop
  89.         # Use next and prev, nextDist, prevDist
  90.         
  91.         # Get Loops centre.
  92.         fac= len(loop)
  93.         verts = me.verts
  94.         self.centre= reduce(lambda a,b: a+verts[b].co/fac, loop, Vector())
  95.         
  96.         # Convert Vert loop to Edges.
  97.         self.edges = [edge(verts[loop[vIdx-1]], verts[loop[vIdx]]) for vIdx in xrange(len(loop))]
  98.         
  99.         if not closed:
  100.             self.edges[0].fake = True # fake edge option
  101.             
  102.         self.closed = closed
  103.             
  104.         
  105.         # Assign linked list
  106.         for eIdx in xrange(len(self.edges)-1):
  107.             self.edges[eIdx].next = self.edges[eIdx+1]
  108.             self.edges[eIdx].prev = self.edges[eIdx-1]
  109.         # Now last
  110.         self.edges[-1].next = self.edges[0]
  111.         self.edges[-1].prev = self.edges[-2]
  112.         
  113.         
  114.         
  115.         # GENERATE AN AVERAGE NORMAL FOR THE WHOLE LOOP.
  116.         self.normal = Vector()
  117.         for e in self.edges:
  118.             n = (self.centre-e.co1).cross(self.centre-e.co2)
  119.             # Do we realy need tot normalize?
  120.             n.normalize()
  121.             self.normal += n
  122.             
  123.             # Generate the angle
  124.             va= e.cent - e.prev.cent
  125.             vb= e.next.cent - e.cent
  126.             
  127.             e.angle= AngleBetweenVecs(va, vb)
  128.         
  129.         # Blur the angles
  130.         #for e in self.edges:
  131.         #    e.angle= (e.angle+e.next.angle)/2
  132.         
  133.         # Blur the angles
  134.         #for e in self.edges:
  135.         #    e.angle= (e.angle+e.prev.angle)/2
  136.             
  137.         self.normal.normalize()
  138.         
  139.         # Generate a normal for each edge.
  140.         for e in self.edges:
  141.             
  142.             n1 = e.co1
  143.             n2 = e.co2
  144.             n3 = e.prev.co1
  145.             
  146.             a = n1-n2
  147.             b = n1-n3
  148.             normal1 = a.cross(b)
  149.             normal1.normalize()
  150.             
  151.             n1 = e.co2
  152.             n3 = e.next.co2
  153.             n2 = e.co1
  154.             
  155.             a = n1-n2
  156.             b = n1-n3
  157.             
  158.             normal2 = a.cross(b)
  159.             normal2.normalize()
  160.             
  161.             # Reuse normal1 var
  162.             normal1 += normal1 + normal2
  163.             normal1.normalize()
  164.             
  165.             e.normal = normal1
  166.             #print e.normal
  167.  
  168.  
  169.         
  170.     def backup(self):
  171.         # Keep a backup of the edges
  172.         self.backup_edges = self.edges[:]
  173.             
  174.     def restore(self):
  175.         self.edges = self.backup_edges[:]
  176.         for e in self.edges:
  177.             e.removed = 0
  178.         
  179.     def reverse(self):
  180.         self.edges.reverse()
  181.         self.normal.negate()
  182.         
  183.         for e in self.edges:
  184.             e.normal.negate()
  185.             e.v1, e.v2 = e.v2, e.v1
  186.             e.co1, e.co2 = e.co2, e.co1
  187.             e.next, e.prev = e.prev, e.next
  188.         
  189.     
  190.     def removeSmallest(self, cullNum, otherLoopLen):
  191.         '''
  192.         Removes N Smallest edges and backs up the loop,
  193.         this is so we can loop between 2 loops as if they are the same length,
  194.         backing up and restoring incase the loop needs to be skinned with another loop of a different length.
  195.         '''
  196.         global CULL_METHOD
  197.         if CULL_METHOD == 1: # Shortest edge
  198.             eloopCopy = self.edges[:]
  199.             
  200.             # Length sort, smallest first
  201.             try:    eloopCopy.sort(key = lambda e1: e1.length)
  202.             except:    eloopCopy.sort(lambda e1, e2: cmp(e1.length, e2.length ))
  203.             
  204.             # Dont use atm
  205.             #eloopCopy.sort(lambda e1, e2: cmp(e1.angle*e1.length, e2.angle*e2.length)) # Length sort, smallest first
  206.             #eloopCopy.sort(lambda e1, e2: cmp(e1.angle, e2.angle)) # Length sort, smallest first
  207.             
  208.             remNum = 0
  209.             for i, e in enumerate(eloopCopy):
  210.                 if not e.fake:
  211.                     e.removed = 1
  212.                     self.edges.remove( e ) # Remove from own list, still in linked list.
  213.                     remNum += 1
  214.                 
  215.                     if not remNum < cullNum:
  216.                         break
  217.             
  218.         else: # CULL METHOD is even
  219.                 
  220.             culled = 0
  221.             
  222.             step = int(otherLoopLen / float(cullNum)) * 2
  223.             
  224.             currentEdge = self.edges[0]
  225.             while culled < cullNum:
  226.                 
  227.                 # Get the shortest face in the next STEP
  228.                 step_count= 0
  229.                 bestAng= 360.0
  230.                 smallestEdge= None
  231.                 while step_count<=step or smallestEdge==None:
  232.                     step_count+=1
  233.                     if not currentEdge.removed: # 0 or -1 will not be accepted
  234.                         if currentEdge.angle<bestAng and not currentEdge.fake:
  235.                             smallestEdge= currentEdge
  236.                             bestAng= currentEdge.angle
  237.                     
  238.                     currentEdge = currentEdge.next
  239.                 
  240.                 # In that stepping length we have the smallest edge.remove it
  241.                 smallestEdge.removed = 1
  242.                 self.edges.remove(smallestEdge)
  243.                 
  244.                 # Start scanning from the edge we found? - result is over fanning- no good.
  245.                 #currentEdge= smallestEdge.next
  246.                 
  247.                 culled+=1
  248.     
  249.  
  250. # Returns face edges.
  251. # face must have edge data.
  252.  
  253. def getSelectedEdges(me, ob):    
  254.     MESH_MODE= Blender.Mesh.Mode()
  255.     
  256.     if MESH_MODE & Blender.Mesh.SelectModes.EDGE or MESH_MODE & Blender.Mesh.SelectModes.VERTEX:
  257.         Blender.Mesh.Mode(Blender.Mesh.SelectModes.EDGE)
  258.         edges= [ ed for ed in me.edges if ed.sel ]
  259.         # print len(edges), len(me.edges)
  260.         Blender.Mesh.Mode(MESH_MODE)
  261.         return edges
  262.     
  263.     elif MESH_MODE & Blender.Mesh.SelectModes.FACE:
  264.         Blender.Mesh.Mode(Blender.Mesh.SelectModes.EDGE)
  265.         
  266.         # value is [edge, face_sel_user_in]
  267.         '''
  268.         try: # Python 2.4 only
  269.             edge_dict=  dict((ed.key, [ed, 0]) for ed in me.edges)
  270.         except:
  271.         '''
  272.         # Cant try 2.4 syntax because python 2.3 will complain still
  273.         edge_dict=  dict([(ed.key, [ed, 0]) for ed in me.edges])
  274.         
  275.         for f in me.faces:
  276.             if f.sel:
  277.                 for edkey in f.edge_keys:
  278.                     edge_dict[edkey][1] += 1
  279.         
  280.         Blender.Mesh.Mode(MESH_MODE)
  281.         return [ ed_data[0] for ed_data in edge_dict.itervalues() if ed_data[1] == 1 ]
  282.     
  283.     
  284.  
  285. def getVertLoops(selEdges, me):
  286.     '''
  287.     return a list of vert loops, closed and open [(loop, closed)...]
  288.     '''
  289.     
  290.     mainVertLoops = []
  291.     # second method
  292.     tot = len(me.verts)
  293.     vert_siblings = [[] for i in xrange(tot)]
  294.     vert_used = [False] * tot
  295.     
  296.     for ed in selEdges:
  297.         i1, i2 = ed.key
  298.         vert_siblings[i1].append(i2)
  299.         vert_siblings[i2].append(i1)
  300.     
  301.     # find the first used vert and keep looping.
  302.     for i in xrange(tot):
  303.         if vert_siblings[i] and not vert_used[i]:
  304.             sbl = vert_siblings[i] # siblings
  305.             
  306.             if len(sbl) > 2:
  307.                 return None
  308.             
  309.             vert_used[i] = True
  310.             
  311.             # do an edgeloop seek
  312.             if len(sbl) == 2:
  313.                 contextVertLoop= [sbl[0], i, sbl[1]] # start the vert loop
  314.                 vert_used[contextVertLoop[ 0]] = True
  315.                 vert_used[contextVertLoop[-1]] = True
  316.             else:
  317.                 contextVertLoop= [i, sbl[0]]
  318.                 vert_used[contextVertLoop[ 1]] = True
  319.             
  320.             # Always seek up
  321.             ok = True
  322.             while ok:
  323.                 ok = False
  324.                 closed = False
  325.                 sbl = vert_siblings[contextVertLoop[-1]]
  326.                 if len(sbl) == 2:
  327.                     next = sbl[not sbl.index( contextVertLoop[-2] )]
  328.                     if vert_used[next]:
  329.                         closed = True
  330.                         # break
  331.                     else:
  332.                         contextVertLoop.append( next ) # get the vert that isnt the second last
  333.                         vert_used[next] = True
  334.                         ok = True
  335.             
  336.             # Seek down as long as the starting vert was not at the edge.
  337.             if not closed and len(vert_siblings[i]) == 2:
  338.                 
  339.                 ok = True
  340.                 while ok:
  341.                     ok = False
  342.                     sbl = vert_siblings[contextVertLoop[0]]
  343.                     if len(sbl) == 2:
  344.                         next = sbl[not sbl.index( contextVertLoop[1] )]
  345.                         if vert_used[next]:
  346.                             closed = True
  347.                         else:
  348.                             contextVertLoop.insert(0, next) # get the vert that isnt the second last
  349.                             vert_used[next] = True
  350.                             ok = True
  351.             
  352.             mainVertLoops.append((contextVertLoop, closed))
  353.     
  354.     
  355.     verts = me.verts
  356.     # convert from indicies to verts
  357.     # mainVertLoops = [([verts[i] for i in contextVertLoop], closed) for contextVertLoop, closed in  mainVertLoops]
  358.     # print len(mainVertLoops)
  359.     return mainVertLoops
  360.     
  361.  
  362.  
  363. def skin2EdgeLoops(eloop1, eloop2, me, ob, MODE):
  364.     
  365.     new_faces= [] # 
  366.     
  367.     # Make sure e1 loops is bigger then e2
  368.     if len(eloop1.edges) != len(eloop2.edges):
  369.         if len(eloop1.edges) < len(eloop2.edges):
  370.             eloop1, eloop2 = eloop2, eloop1
  371.         
  372.         eloop1.backup() # were about to cull faces
  373.         CULL_FACES = len(eloop1.edges) - len(eloop2.edges)
  374.         eloop1.removeSmallest(CULL_FACES, len(eloop1.edges))
  375.     else:
  376.         CULL_FACES = 0
  377.     # First make sure poly vert loops are in sync with eachother.
  378.     
  379.     # The vector allong which we are skinning.
  380.     skinVector = eloop1.centre - eloop2.centre
  381.     
  382.     loopDist = skinVector.length
  383.     
  384.     # IS THE LOOP FLIPPED, IF SO FLIP BACK. we keep it flipped, its ok,
  385.     if eloop1.closed or eloop2.closed:
  386.         angleBetweenLoopNormals = AngleBetweenVecs(eloop1.normal, eloop2.normal)
  387.         if angleBetweenLoopNormals > 90:
  388.             eloop2.reverse()
  389.             
  390.  
  391.         DIR= eloop1.centre - eloop2.centre
  392.         
  393.         # if eloop2.closed:
  394.         bestEloopDist = BIG_NUM
  395.         bestOffset = 0
  396.         # Loop rotation offset to test.1
  397.         eLoopIdxs = range(len(eloop1.edges))
  398.         for offset in xrange(len(eloop1.edges)):
  399.             totEloopDist = 0 # Measure this total distance for thsi loop.
  400.             
  401.             offsetIndexLs = eLoopIdxs[offset:] + eLoopIdxs[:offset] # Make offset index list
  402.             
  403.             
  404.             # e1Idx is always from 0uu to N, e2Idx is offset.
  405.             for e1Idx, e2Idx in enumerate(offsetIndexLs):
  406.                 e1= eloop1.edges[e1Idx]
  407.                 e2= eloop2.edges[e2Idx]
  408.                 
  409.                 
  410.                 # Include fan connections in the measurement.
  411.                 OK= True
  412.                 while OK or e1.removed:
  413.                     OK= False
  414.                     
  415.                     # Measure the vloop distance ===============
  416.                     diff= ((e1.cent - e2.cent).length) #/ nangle1
  417.                     
  418.                     ed_dir= e1.cent-e2.cent
  419.                     a_diff= AngleBetweenVecs(DIR, ed_dir)/18 # 0 t0 18
  420.                     
  421.                     totEloopDist += (diff * (1+a_diff)) / (1+loopDist)
  422.                     
  423.                     # Premeture break if where no better off
  424.                     if totEloopDist > bestEloopDist:
  425.                         break
  426.                     
  427.                     e1=e1.next
  428.                     
  429.             if totEloopDist < bestEloopDist:
  430.                 bestOffset = offset
  431.                 bestEloopDist = totEloopDist
  432.         
  433.         # Modify V2 LS for Best offset
  434.         eloop2.edges = eloop2.edges[bestOffset:] + eloop2.edges[:bestOffset]
  435.             
  436.     else:
  437.         # Both are open loops, easier to calculate.
  438.         
  439.         
  440.         # Make sure the fake edges are at the start.
  441.         for i, edloop in enumerate((eloop1, eloop2)):
  442.             # print "LOOPO"
  443.             if edloop.edges[0].fake:
  444.                 # alredy at the start
  445.                 #print "A"
  446.                 pass
  447.             elif edloop.edges[-1].fake:
  448.                 # put the end at the start
  449.                 edloop.edges.insert(0, edloop.edges.pop())
  450.                 #print "B"
  451.                 
  452.             else:
  453.                 for j, ed in enumerate(edloop.edges):
  454.                     if ed.fake:
  455.                         #print "C"
  456.                         edloop.edges = edloop.edges = edloop.edges[j:] + edloop.edges[:j]
  457.                         break
  458.         # print "DONE"
  459.         ed1, ed2 = eloop1.edges[0], eloop2.edges[0]
  460.         
  461.         if not ed1.fake or not ed2.fake:
  462.             raise "Error"
  463.         
  464.         # Find the join that isnt flipped (juts like detecting a bow-tie face)
  465.         a1 = (ed1.co1 - ed2.co1).length + (ed1.co2 - ed2.co2).length
  466.         a2 = (ed1.co1 - ed2.co2).length + (ed1.co2 - ed2.co1).length
  467.         
  468.         if a1 > a2:
  469.             eloop2.reverse()
  470.             # make the first edge the start edge still
  471.             eloop2.edges.insert(0, eloop2.edges.pop())
  472.     
  473.     
  474.     
  475.     
  476.     for loopIdx in xrange(len(eloop2.edges)):
  477.         e1 = eloop1.edges[loopIdx]
  478.         e2 = eloop2.edges[loopIdx]
  479.         
  480.         # Remember the pairs for fan filling culled edges.
  481.         e1.match = e2; e2.match = e1
  482.         
  483.         if not (e1.fake or e2.fake):
  484.             new_faces.append([e1.v1, e1.v2, e2.v2, e2.v1])
  485.     
  486.     # FAN FILL MISSING FACES.
  487.     if CULL_FACES:
  488.         # Culled edges will be in eloop1.
  489.         FAN_FILLED_FACES = 0
  490.         
  491.         contextEdge = eloop1.edges[0] # The larger of teh 2
  492.         while FAN_FILLED_FACES < CULL_FACES:
  493.             while contextEdge.next.removed == 0:
  494.                 contextEdge = contextEdge.next
  495.             
  496.             vertFanPivot = contextEdge.match.v2
  497.             
  498.             while contextEdge.next.removed == 1:
  499.                 #if not contextEdge.next.fake:
  500.                 new_faces.append([contextEdge.next.v1, contextEdge.next.v2, vertFanPivot])
  501.                 
  502.                 # Should we use another var?, this will work for now.
  503.                 contextEdge.next.removed = 1
  504.                 
  505.                 contextEdge = contextEdge.next
  506.                 FAN_FILLED_FACES += 1
  507.         
  508.         # may need to fan fill backwards 1 for non closed loops.
  509.         
  510.         eloop1.restore() # Add culled back into the list.
  511.     
  512.     return new_faces
  513.  
  514. def main():
  515.     global CULL_METHOD
  516.     
  517.     is_editmode = Window.EditMode()
  518.     if is_editmode: Window.EditMode(0)
  519.     ob = bpy.data.scenes.active.objects.active
  520.     if ob == None or ob.type != 'Mesh':
  521.         BPyMessages.Error_NoMeshActive()
  522.         return
  523.     
  524.     me = ob.getData(mesh=1)
  525.     
  526.     if me.multires:
  527.         BPyMessages.Error_NoMeshMultiresEdit()
  528.         return
  529.     
  530.     time1 = Blender.sys.time()
  531.     selEdges = getSelectedEdges(me, ob)
  532.     vertLoops = getVertLoops(selEdges, me) # list of lists of edges.
  533.     if vertLoops == None:
  534.         PupMenu('Error%t|Selection includes verts that are a part of more then 1 loop')
  535.         if is_editmode: Window.EditMode(1)
  536.         return
  537.     # print len(vertLoops)
  538.     
  539.     
  540.     if len(vertLoops) > 2:
  541.         choice = PupMenu('Loft '+str(len(vertLoops))+' edge loops%t|loop|segment')
  542.         if choice == -1:
  543.             if is_editmode: Window.EditMode(1)
  544.             return
  545.     elif len(vertLoops) < 2:
  546.         PupMenu('Error%t|No Vertloops found!')
  547.         if is_editmode: Window.EditMode(1)    
  548.         return
  549.     else:
  550.         choice = 2
  551.     
  552.     
  553.     # The line below checks if any of the vert loops are differenyt in length.
  554.     if False in [len(v[0]) == len(vertLoops[0][0]) for v in vertLoops]:
  555.         CULL_METHOD = PupMenu('Small to large edge loop distrobution method%t|remove edges evenly|remove smallest edges')
  556.         if CULL_METHOD == -1:
  557.             if is_editmode: Window.EditMode(1)
  558.             return
  559.         
  560.         if CULL_METHOD ==1: # RESET CULL_METHOD
  561.             CULL_METHOD = 0 # shortest
  562.         else:
  563.             CULL_METHOD = 1 # even
  564.     
  565.     
  566.     time1 = Blender.sys.time()
  567.     # Convert to special edge data.
  568.     edgeLoops = []
  569.     for vloop, closed in vertLoops:
  570.         edgeLoops.append(edgeLoop(vloop, me, closed))
  571.         
  572.     
  573.     # VERT LOOP ORDERING CODE
  574.     # "Build a worm" list - grow from Both ends
  575.     edgeOrderedList = [edgeLoops.pop()]
  576.     
  577.     # Find the closest.
  578.     bestSoFar = BIG_NUM
  579.     bestIdxSoFar = None
  580.     for edLoopIdx, edLoop in enumerate(edgeLoops):
  581.         l =(edgeOrderedList[-1].centre - edLoop.centre).length 
  582.         if l < bestSoFar:
  583.             bestIdxSoFar = edLoopIdx
  584.             bestSoFar = l
  585.             
  586.     edgeOrderedList.append( edgeLoops.pop(bestIdxSoFar) )
  587.     
  588.     # Now we have the 2 closest, append to either end-
  589.     # Find the closest.
  590.     while edgeLoops:
  591.         bestSoFar = BIG_NUM
  592.         bestIdxSoFar = None
  593.         first_or_last = 0 # Zero is first
  594.         for edLoopIdx, edLoop in enumerate(edgeLoops):
  595.             l1 =(edgeOrderedList[-1].centre - edLoop.centre).length 
  596.             
  597.             if l1 < bestSoFar:
  598.                 bestIdxSoFar = edLoopIdx
  599.                 bestSoFar = l1
  600.                 first_or_last = 1 # last
  601.             
  602.             l2 =(edgeOrderedList[0].centre - edLoop.centre).length 
  603.             if l2 < bestSoFar:
  604.                 bestIdxSoFar = edLoopIdx
  605.                 bestSoFar = l2
  606.                 first_or_last = 0 # last
  607.         
  608.         if first_or_last: # add closest Last
  609.             edgeOrderedList.append( edgeLoops.pop(bestIdxSoFar) )    
  610.         else: # Add closest First
  611.             edgeOrderedList.insert(0, edgeLoops.pop(bestIdxSoFar) )     # First
  612.     
  613.     faces = []
  614.     
  615.     for i in xrange(len(edgeOrderedList)-1):
  616.         faces.extend( skin2EdgeLoops(edgeOrderedList[i], edgeOrderedList[i+1], me, ob, 0) )
  617.     if choice == 1 and len(edgeOrderedList) > 2: # Loop
  618.         faces.extend( skin2EdgeLoops(edgeOrderedList[0], edgeOrderedList[-1], me, ob, 0) )
  619.     
  620.     # REMOVE SELECTED FACES.
  621.     MESH_MODE= Blender.Mesh.Mode()
  622.     if MESH_MODE & Blender.Mesh.SelectModes.EDGE or MESH_MODE & Blender.Mesh.SelectModes.VERTEX: pass
  623.     elif MESH_MODE & Blender.Mesh.SelectModes.FACE:
  624.         try: me.faces.delete(1, [ f for f in me.faces if f.sel ])
  625.         except: pass
  626.     
  627.     me.faces.extend(faces, smooth = True)
  628.     
  629.     print '\nSkin done in %.4f sec.' % (Blender.sys.time()-time1)
  630.     
  631.     
  632.     if is_editmode: Window.EditMode(1)
  633.  
  634. if __name__ == '__main__':
  635.     main()
  636.